package com.hoshiicloud.gateway.filter;

import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hoshiicloud.auth.vo.LoginVO;
import com.hoshiicloud.common.constant.TokenUserFieldEnum;
import com.hoshiicloud.common.constant.UserTypeEnum;
import com.hoshiicloud.common.exception.ServiceException;
import com.hoshiicloud.common.rpc.Response;
import com.hoshiicloud.common.utils.token.JWTUtil;
import com.hoshiicloud.gateway.feign.AuthService;
import com.hoshiicloud.gateway.util.FilterUtil;
import com.hoshiicloud.gateway.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerErrorException;
import org.springframework.web.server.ServerWebExchange;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @program: hoshiibuy
 * @description: jwt验证过滤器
 * @author: Mr.wu
 * @create: 2019-06-21 18:41
 **/
@Slf4j
public class JwtCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<JwtCheckGatewayFilterFactory.Config> {

    public JwtCheckGatewayFilterFactory() {
        super(Config.class);
    }

    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private AuthService authService;

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            /**
             * 1.检查header是否携带统一登录票据和clientId
             * 2.如携带票据则先从cookie获取令牌,如无令牌则主动获取，并写入header和cookie
             * 2.如携带票据则获取子系统令牌并写入header和cookie
             * 3.如未携带则返回未授权错误
             */
            String requestUri = exchange.getRequest().getURI().getPath();
            log.info("请求地址{}", requestUri);
            if (config.getExceptionUrl() != null) {
                log.info("例外url:" + config.getExceptionUrl().toString());
            }
            if (config.getExceptionUrl() != null && config.getExceptionUrl().contains(requestUri)) {
                log.info("请求例外url,检查通过");
                return chain.filter(exchange);
            }

            String token = exchange.getRequest().getHeaders().getFirst("token");
            String clientType = exchange.getRequest().getHeaders().getFirst("clientType");
            String clientId = exchange.getRequest().getHeaders().getFirst("clientId");
            DecodedJWT ticketJwt = JWTUtil.getDecodedJWT(token);

            String redisTicket = (String) redisTemplate.opsForValue()
                    .get(ticketJwt.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString());
            if (StringUtils.isBlank(token) || StringUtils.isBlank(clientId)
                    || redisTemplate.opsForValue().get(ticketJwt.getClaim(TokenUserFieldEnum.LOGIN_KEY.getName()).asString()) == null) {
                //没有租户会员票据，返回401
                return FilterUtil.getUnauthResponse(exchange.getResponse());
            }
            String jwtToken = "";
            HttpCookie cookie = exchange.getRequest().getCookies().getFirst(clientId + "Token");
            if (cookie != null) {
                jwtToken = exchange.getRequest().getCookies().getFirst(clientId + "Token").getValue();
            }

            if (StringUtils.isBlank(jwtToken) || TokenUtil.isTokenExpired(jwtToken) || redisTemplate.opsForValue().get(jwtToken) == null) {
                //校验有效期,未过期则通过
                //未过期到redis查询,如未存在则签发新token
                Response result = null;
                UserTypeEnum clientTypeEnum=UserTypeEnum.get(clientType);
                switch (clientTypeEnum) {
                    case MEMBER:
                        //TODO 修改为comuser接口
                        result = authService.memberAccessToken(token);
                        break;
                    case STORE:
                        result = authService.storeLogin(Long.valueOf(clientId), token);
                        break;
                    case COMPANY:
                        result=authService.companyUserLogin(token);
                        break;
                    case PLATFORM:
                        result=authService.platformLogin(Long.valueOf(clientId),token);
                        break;
                    case LESSEE_VENDOR:
                        break;
                    case PLATFORM_VENDOR:
                        break;
                    case STORE_VENDOR:
                        break;
                    case PLAT_CONSUMERS:
                        break;
                    default:
                        throw new ServiceException("登录失败");
                }

                if (result != null && result.isSuccess()) {
                    LoginVO loginVO = (LoginVO) result.getData();
                    jwtToken = loginVO.getAccessToken();
                    HttpCookie httpCookie = new HttpCookie(clientId + "Token", jwtToken);
                    ResponseCookie responseCookie = ResponseCookie.from(clientId + "Token", jwtToken).path("/").build();
                    /*
                    List<HttpCookie> list=new ArrayList<HttpCookie>();
                    list.add(httpCookie);
                     */
                    //exchange.getRequest().getCookies().put(clientId+"Token",list);
                    exchange.getResponse().getCookies().remove(clientId + "Token");
                    exchange.getResponse().addCookie(responseCookie);
                    //向headers中放token
                    ServerHttpRequest host = exchange.getRequest().mutate().header("X-Token", jwtToken).build();
                    //将现在的request 变成 change对象
                    ServerWebExchange build = exchange.mutate().request(host).build();
                    return chain.filter(build);
                } else {
                    //获取令牌失败，暂时返回401
                    //return FilterUtil.getUnauthResponse(exchange.getResponse());
                    return FilterUtil.getFailedResponse(exchange.getResponse(),result);
                }
            } else {
                //向headers中放文件，记得build
                ServerHttpRequest host = exchange.getRequest().mutate().header("X-Token", jwtToken).build();
                //将现在的request 变成 change对象
                ServerWebExchange build = exchange.mutate().request(host).build();
                return chain.filter(build);
            }
        };
    }

    public static class Config {

        //Put the configuration properties for your filter here
        private List<String> exceptionUrl;

        public List<String> getExceptionUrl() {
            return exceptionUrl;
        }

        public void setExceptionUrl(String exceptionUrl) {
            this.exceptionUrl = Arrays.asList(exceptionUrl.split("&"));
        }
    }
}
